package nosqls

import (
	"fmt"
	"time"

	redis "github.com/redis/go-redis/v9"
)

// NoSQL 结构体用于存储NoSQL数据库连接配置信息
// 该结构体包含了连接NoSQL数据库所需的各种参数和连接池配置
type RedisConfig struct {
	// Name NoSQL配置名称，用于标识不同的NoSQL连接配置
	Name string `json:"name"`
	// Type NoSQL类型，如 redis-single、redis-sentinel、redis-cluster 等
	Type string `json:"type"`
	// Address 服务器地址，单节点为string，集群/哨兵为[]string
	Address []string `json:"address"`
	// Database 数据库编号（主要用于Redis）
	Database int `json:"database"`
	// Username 连接用户名
	Username string `json:"username"`
	// Password 连接密码
	Password string `json:"password"`
	// MasterName 主节点名称（哨兵模式专用）
	MasterName string `json:"master_name"`
	// MaxRetries 最大重试次数
	MaxRetries int `json:"max_retries"`
	// PoolSize 连接池大小
	PoolSize int `json:"pool_size"`
	// MinIdleConns 最小空闲连接数
	MinIdleConns int `json:"min_idle_conns"`
	// MaxConnAge 连接最大生存时间（秒）
	MaxConnAge int `json:"max_conn_age"`
	// EnableTracing 是否启用追踪
	EnableTracing bool `json:"enable_tracing"`
	// EnableMetrics 是否启用监控
	EnableMetrics bool `json:"enable_metrics"`
}

// RedisClient 统一的可用客户端接口：
// - 包含所有常用命令（Cmdable）
// - 具备 Close() 能力
// *redis.Client 与 *redis.ClusterClient 均实现该接口
type RedisClient interface {
	redis.Cmdable
	Close() error
}

// InitNosqlter 是NoSQL数据库初始化接口
type InitNosqlter interface {
	InitRedis() RedisClient
}

// InitRedis 初始化NoSQL连接并返回统一的 RedisClient
// - redis-single / redis-sentinel: 返回 *redis.Client
// - redis-cluster: 返回 *redis.ClusterClient
func (d *RedisConfig) InitRedis() RedisClient {
	var client RedisClient

	switch d.Type {
	case "redis-single":
		ds := RedisSingleConfig(*d)
		client = ds.InitRedis()
	case "redis-sentinel":
		ds := RedisSentinelConfig(*d)
		client = ds.InitRedis()
	case "redis-cluster":
		ds := RedisClusterConfig(*d)
		client = ds.InitRedis()
	default:
		panic(fmt.Sprintf("Unsupported NoSQL type: %s", d.Type))
	}

	// 配置连接池参数（在内部做断言，调用方无需关心具体类型）
	switch c := client.(type) {
	case *redis.Client:
		opt := c.Options()
		opt.MaxRetries = d.MaxRetries
		opt.PoolSize = d.PoolSize
		opt.MinIdleConns = d.MinIdleConns
		if d.MaxConnAge > 0 {
			// go-redis 推荐使用 MaxConnAge 控制连接最大生存时间
			opt.ConnMaxLifetime = time.Duration(d.MaxConnAge) * time.Second
		}
	case *redis.ClusterClient:
		opt := c.Options()
		opt.MaxRetries = d.MaxRetries
		opt.PoolSize = d.PoolSize
		opt.MinIdleConns = d.MinIdleConns
		if d.MaxConnAge > 0 {
			opt.ConnMaxLifetime = time.Duration(d.MaxConnAge) * time.Second
		}
	}

	return client
}
